// pkg/ublk/backend.go
package ublk

import (
	"context"
	"fmt"
	"log"
	"os"
	"sync"
)

// Backend ublk 块设备后端
type Backend struct {
	rootDir    string
	devices    map[uint32]*Device
	mu         sync.RWMutex
	nextDevID  uint32
	downloader *Downloader
}

// Device 代表一个 ublk 块设备
type Device struct {
	ID        uint32
	Size      int64
	BlockSize int64
	DataURL   string
	ChunkSize int64

	// 块缓存
	blockCache map[int64][]byte
	cacheMu    sync.RWMutex

	// 未完成的请求
	pendingReqs map[uint64]*Request
	reqMu       sync.RWMutex
}

// Request 代表一个块 I/O 请求
type Request struct {
	ID     uint64
	OpCode int
	Addr   uint64 // 请求的起始地址
	Len    uint32 // 请求的字节数
	Buffer []byte
}

// NewBackend 创建 ublk 后端
func NewBackend(rootDir string) (*Backend, error) {
	if err := os.MkdirAll(rootDir, 0o755); err != nil {
		return nil, err
	}

	return &Backend{
		rootDir:   rootDir,
		devices:   make(map[uint32]*Device),
		nextDevID: 0,
	}, nil
}

// CreateDevice 创建新的块设备
func (b *Backend) CreateDevice(ctx context.Context, size int64, dataURL string, chunkSize int64) (*Device, error) {
	b.mu.Lock()
	devID := b.nextDevID
	b.nextDevID++
	b.mu.Unlock()

	dev := &Device{
		ID:          devID,
		Size:        size,
		BlockSize:   4096, // 标准块大小
		DataURL:     dataURL,
		ChunkSize:   chunkSize,
		blockCache:  make(map[int64][]byte),
		pendingReqs: make(map[uint64]*Request),
	}

	b.mu.Lock()
	b.devices[devID] = dev
	b.mu.Unlock()

	log.Printf("Created ublk device %d: size=%d, chunkSize=%d", devID, size, chunkSize)
	return dev, nil
}

// HandleIORequest 处理块 I/O 请求
func (b *Backend) HandleIORequest(ctx context.Context, devID uint32, req *Request) ([]byte, error) {
	b.mu.RLock()
	dev, exists := b.devices[devID]
	b.mu.RUnlock()

	if !exists {
		return nil, fmt.Errorf("device %d not found", devID)
	}

	// 边界检查
	if req.Addr+uint64(req.Len) > uint64(dev.Size) {
		return nil, fmt.Errorf("request out of bounds")
	}

	switch req.OpCode {
	case OP_READ:
		return b.handleRead(ctx, dev, req)
	case OP_WRITE:
		return b.handleWrite(ctx, dev, req)
	case OP_FLUSH:
		return b.handleFlush(ctx, dev, req)
	default:
		return nil, fmt.Errorf("unsupported operation: %d", req.OpCode)
	}
}

// handleRead 处理读请求
func (b *Backend) handleRead(ctx context.Context, dev *Device, req *Request) ([]byte, error) {
	buffer := make([]byte, req.Len)
	offset := int64(req.Addr)
	remaining := int64(req.Len)

	for remaining > 0 {
		// 确定所需的块
		blockIndex := offset / dev.BlockSize
		blockOffset := offset % dev.BlockSize
		blockRemaining := dev.BlockSize - blockOffset

		if blockRemaining > remaining {
			blockRemaining = remaining
		}

		// 从缓存或远程获取块
		blockData, err := b.getBlock(ctx, dev, blockIndex)
		if err != nil {
			return nil, fmt.Errorf("failed to get block %d: %w", blockIndex, err)
		}

		// 复制到缓冲区
		copy(buffer[req.Len-uint32(remaining):], blockData[blockOffset:blockOffset+blockRemaining])

		offset += blockRemaining
		remaining -= blockRemaining
	}

	return buffer, nil
}

// handleWrite 处理写请求（块设备为只读）
func (b *Backend) handleWrite(ctx context.Context, dev *Device, req *Request) ([]byte, error) {
	// ublk 设备配置为只读，写请求应被拒绝
	return nil, fmt.Errorf("device is read-only")
}

// handleFlush 处理 flush 请求
func (b *Backend) handleFlush(ctx context.Context, dev *Device, req *Request) ([]byte, error) {
	// 对于只读设备，flush 是 no-op
	return []byte{}, nil
}

// getBlock 获取块数据
func (b *Backend) getBlock(ctx context.Context, dev *Device, blockIndex int64) ([]byte, error) {
	dev.cacheMu.RLock()
	if cached, exists := dev.blockCache[blockIndex]; exists {
		dev.cacheMu.RUnlock()
		return cached, nil
	}
	dev.cacheMu.RUnlock()

	// 从远程按块下载
	blockOffset := blockIndex * dev.BlockSize
	blockSize := dev.BlockSize
	if blockOffset+blockSize > dev.Size {
		blockSize = dev.Size - blockOffset
	}

	// 按需下载块
	blockData, err := b.downloadBlock(ctx, dev, blockOffset, blockSize)
	if err != nil {
		return nil, err
	}

	// 缓存块
	dev.cacheMu.Lock()
	dev.blockCache[blockIndex] = blockData
	dev.cacheMu.Unlock()

	return blockData, nil
}

// downloadBlock 从远程下载块
func (b *Backend) downloadBlock(ctx context.Context, dev *Device, offset, size int64) ([]byte, error) {
	// TODO: 实现 HTTP Range 请求
	// 这里暂时返回零填充的块
	return make([]byte, size), nil
}

// RemoveDevice 移除块设备
func (b *Backend) RemoveDevice(devID uint32) error {
	b.mu.Lock()
	defer b.mu.Unlock()

	if _, exists := b.devices[devID]; !exists {
		return fmt.Errorf("device %d not found", devID)
	}

	delete(b.devices, devID)
	log.Printf("Removed ublk device %d", devID)
	return nil
}

// Close 关闭后端
func (b *Backend) Close() error {
	b.mu.Lock()
	defer b.mu.Unlock()

	for devID := range b.devices {
		delete(b.devices, devID)
	}
	return nil
}

// 操作码常量
const (
	OP_READ  = 0
	OP_WRITE = 1
	OP_FLUSH = 2
)

// ---
